package com.yc.cloud.admin.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yc.cloud.admin.config.FaceRecognitionProperties;
import com.yc.cloud.admin.dto.request.FaceAddFileReqDTO;
import com.yc.cloud.admin.dto.request.FaceDetectReqDTO;
import com.yc.cloud.admin.dto.response.BaseFaceResponse;
import com.yc.cloud.admin.dto.response.FaceAddFileRespDTO;
import com.yc.cloud.admin.dto.response.FaceDetectRespDTO;
import com.yc.cloud.admin.dto.response.FaceSearchRespDTO;
import com.yc.cloud.admin.service.FaceRecognitionService;
import com.yc.cloud.common.basic.exception.Asserts;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.MediaType;
import org.springframework.http.client.MultipartBodyBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * 人脸识别服务实现类
 *
 * @author JackGu
 * @since 2025-11-05
 */
@Slf4j
@Service
public class FaceRecognitionServiceImpl implements FaceRecognitionService {

    @Resource
    private FaceRecognitionProperties faceRecognitionProperties;

    @Resource(name = "faceRecognitionWebClient")
    private WebClient faceRecognitionWebClient;

    @Resource
    private ObjectMapper objectMapper;

    @Override
    public FaceDetectRespDTO detectFace(FaceDetectReqDTO reqDTO) {
        if (StrUtil.isBlank(reqDTO.getImage())) {
            Asserts.fail("图片数据不能为空");
        }

        try {
            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("image", reqDTO.getImage());
            
            if (StrUtil.isNotBlank(reqDTO.getFaceId())) {
                requestBody.put("face_id", reqDTO.getFaceId());
            }
            
            if (reqDTO.getThreshold() != null) {
                requestBody.put("threshold", reqDTO.getThreshold());
            }

            // 发送请求
            String url = faceRecognitionProperties.getDetectUrl();
            log.info("调用人脸检测接口: {}, 请求参数: {}", url, JSONUtil.toJsonStr(requestBody));

            String responseBody = faceRecognitionWebClient.post()
                    .uri(url)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(requestBody)
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofMillis(faceRecognitionProperties.getReadTimeout()))
                    .block();

            log.info("人脸检测接口响应: {}", responseBody);

            // 解析响应（使用 ObjectMapper 正确处理泛型）
            if (StrUtil.isNotBlank(responseBody)) {
                return objectMapper.readValue(responseBody, FaceDetectRespDTO.class);
            } else {
                log.error("人脸检测接口调用失败: 响应为空");
                Asserts.fail("人脸检测失败");
            }

        } catch (Exception e) {
            log.error("调用人脸检测接口异常", e);
            Asserts.fail("人脸检测服务异常: " + e.getMessage());
        }

        return null;
    }

    @Override
    public FaceAddFileRespDTO addFaceFile(MultipartFile file, FaceAddFileReqDTO reqDTO) {
        if (file == null || file.isEmpty()) {
            Asserts.fail("人脸图片文件不能为空");
        }

        if (reqDTO == null || StrUtil.isBlank(reqDTO.getPersonId())) {
            Asserts.fail("人员ID不能为空");
        }

        try {
            // 构建multipart/form-data请求
            MultipartBodyBuilder builder = new MultipartBodyBuilder();
            
            // 添加文件
            builder.part("file", new ByteArrayResource(file.getBytes()) {
                @Override
                public String getFilename() {
                    return file.getOriginalFilename();
                }
            });
            
            // 添加其他参数（按照API文档的参数名）
            builder.part("person_id", reqDTO.getPersonId());
            
            if (StrUtil.isNotBlank(reqDTO.getPersonName())) {
                builder.part("person_name", reqDTO.getPersonName());
            }
            
            if (StrUtil.isNotBlank(reqDTO.getMetaInfo())) {
                builder.part("meta_info", reqDTO.getMetaInfo());
            }

            // 发送请求
            String url = faceRecognitionProperties.getAddFileUrl();
            log.info("调用添加人脸文件接口: {}, personId: {}, personName: {}", 
                    url, reqDTO.getPersonId(), reqDTO.getPersonName());

            String responseBody = faceRecognitionWebClient.post()
                    .uri(url)
                    .contentType(MediaType.MULTIPART_FORM_DATA)
                    .body(BodyInserters.fromMultipartData(builder.build()))
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofMillis(faceRecognitionProperties.getReadTimeout()))
                    .block();

            log.info("添加人脸文件接口响应: {}", responseBody);

            // 解析响应（使用 ObjectMapper 正确处理泛型）
            if (StrUtil.isNotBlank(responseBody)) {
                return objectMapper.readValue(responseBody, FaceAddFileRespDTO.class);
            } else {
                log.error("添加人脸文件接口调用失败: 响应为空");
                Asserts.fail("添加人脸失败");
            }

        } catch (IOException e) {
            log.error("读取文件异常", e);
            Asserts.fail("读取文件失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("调用添加人脸文件接口异常", e);
            Asserts.fail("添加人脸服务异常: " + e.getMessage());
        }

        return null;
    }

    @Override
    public FaceAddFileRespDTO addFaceFile(File file, FaceAddFileReqDTO reqDTO) {
        if (file == null || !file.exists() || !file.isFile()) {
            Asserts.fail("人脸图片文件不存在或无效");
        }

        if (reqDTO == null || StrUtil.isBlank(reqDTO.getPersonId())) {
            Asserts.fail("人员ID不能为空");
        }

        try {
            // 读取文件内容
            byte[] fileBytes = Files.readAllBytes(file.toPath());
            
            // 构建multipart/form-data请求
            MultipartBodyBuilder builder = new MultipartBodyBuilder();
            
            // 添加文件
            builder.part("file", new ByteArrayResource(fileBytes) {
                @Override
                public String getFilename() {
                    return file.getName();
                }
            });
            
            // 添加其他参数（按照API文档的参数名）
            builder.part("person_id", reqDTO.getPersonId());
            
            if (StrUtil.isNotBlank(reqDTO.getPersonName())) {
                builder.part("person_name", reqDTO.getPersonName());
            }
            
            if (StrUtil.isNotBlank(reqDTO.getMetaInfo())) {
                builder.part("meta_info", reqDTO.getMetaInfo());
            }

            // 发送请求
            String url = faceRecognitionProperties.getAddFileUrl();
            log.info("调用添加人脸文件接口: {}, personId: {}, personName: {}, filePath: {}", 
                    url, reqDTO.getPersonId(), reqDTO.getPersonName(), file.getAbsolutePath());

            String responseBody = faceRecognitionWebClient.post()
                    .uri(url)
                    .contentType(MediaType.MULTIPART_FORM_DATA)
                    .body(BodyInserters.fromMultipartData(builder.build()))
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofMillis(faceRecognitionProperties.getReadTimeout()))
                    .block();

            log.info("添加人脸文件接口响应: {}", responseBody);

            // 解析响应（使用 ObjectMapper 正确处理泛型）
            if (StrUtil.isNotBlank(responseBody)) {
                return objectMapper.readValue(responseBody, FaceAddFileRespDTO.class);
            } else {
                log.error("添加人脸文件接口调用失败: 响应为空");
                Asserts.fail("添加人脸失败");
            }

        } catch (IOException e) {
            log.error("读取文件异常: {}", file.getAbsolutePath(), e);
            Asserts.fail("读取文件失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("调用添加人脸文件接口异常", e);
            Asserts.fail("添加人脸服务异常: " + e.getMessage());
        }

        return null;
    }

    @Override
    public FaceDetectRespDTO compareFace(String imageBase64, String faceId, Float threshold) {
        if (StrUtil.isBlank(imageBase64)) {
            Asserts.fail("待比对的图片数据不能为空");
        }

        if (StrUtil.isBlank(faceId)) {
            Asserts.fail("人脸ID不能为空");
        }

        FaceDetectReqDTO reqDTO = new FaceDetectReqDTO();
        reqDTO.setImage(imageBase64);
        reqDTO.setFaceId(faceId);
        reqDTO.setThreshold(threshold != null ? threshold : 0.6f);

        return detectFace(reqDTO);
    }

    @Override
    public FaceDetectRespDTO compareFaceByFile(MultipartFile file, String faceId, Float threshold) {
        if (file == null || file.isEmpty()) {
            Asserts.fail("待比对的图片文件不能为空");
        }

        try {
            // 将文件转换为Base64
            byte[] fileBytes = file.getBytes();
            String imageBase64 = Base64.encode(fileBytes);

            return compareFace(imageBase64, faceId, threshold);

        } catch (IOException e) {
            log.error("读取文件异常", e);
            Asserts.fail("读取文件失败: " + e.getMessage());
        }

        return null;
    }

    @Override
    public Boolean deleteFace(String faceId) {
        if (StrUtil.isBlank(faceId)) {
            log.warn("删除人脸失败: faceId为空");
            return false;
        }

        try {
            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("faceId", faceId);

            // 发送请求
            String url = faceRecognitionProperties.getDeleteUrl();
            log.info("调用删除人脸接口: {}, faceId: {}", url, faceId);

            String responseBody = faceRecognitionWebClient.method(org.springframework.http.HttpMethod.DELETE)
                    .uri(url)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(requestBody)
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofMillis(faceRecognitionProperties.getReadTimeout()))
                    .block();

            log.info("删除人脸接口响应: {}", responseBody);

            // 解析响应
            if (StrUtil.isNotBlank(responseBody)) {
                BaseFaceResponse<?> result = objectMapper.readValue(responseBody, BaseFaceResponse.class);
                if (result != null && result.isSuccess()) {
                    log.info("人脸删除成功: faceId={}", faceId);
                    return true;
                } else {
                    log.error("人脸删除失败: faceId={}, message={}", 
                            faceId, result != null ? result.getMsg() : "未知错误");
                    return false;
                }
            } else {
                log.error("删除人脸接口调用失败: 响应为空");
                return false;
            }

        } catch (Exception e) {
            log.error("调用删除人脸接口异常: faceId={}", faceId, e);
            return false;
        }
    }

    @Override
    public Boolean existsFace(String faceId) {
        // TODO: 根据实际API接口补充查询人脸的逻辑
        log.warn("查询人脸是否存在功能暂未实现: faceId={}", faceId);
        return false;
    }

    @Override
    public FaceSearchRespDTO searchFaceByFile(MultipartFile file, Float threshold, Integer topK) {
        if (file == null || file.isEmpty()) {
            Asserts.fail("待搜索的图片文件不能为空");
        }

        try {
            // 构建multipart/form-data请求
            MultipartBodyBuilder builder = new MultipartBodyBuilder();
            
            // 添加文件
            builder.part("file", new ByteArrayResource(file.getBytes()) {
                @Override
                public String getFilename() {
                    return file.getOriginalFilename();
                }
            });
            
            // 添加其他参数
            if (threshold != null) {
                builder.part("threshold", threshold);
            }
            
            if (topK != null) {
                builder.part("top_k", topK);
            }

            // 发送请求
            String url = faceRecognitionProperties.getSearchFileUrl();
            log.info("调用人脸搜索文件接口: {}, threshold: {}, topK: {}", url, threshold, topK);

            String responseBody = faceRecognitionWebClient.post()
                    .uri(url)
                    .contentType(MediaType.MULTIPART_FORM_DATA)
                    .body(BodyInserters.fromMultipartData(builder.build()))
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofMillis(faceRecognitionProperties.getReadTimeout()))
                    .block();

            log.info("人脸搜索文件接口响应: {}", responseBody);

            // 解析响应（使用 ObjectMapper 正确处理泛型）
            if (StrUtil.isNotBlank(responseBody)) {
                return objectMapper.readValue(responseBody, FaceSearchRespDTO.class);
            } else {
                log.error("人脸搜索文件接口调用失败: 响应为空");
                Asserts.fail("人脸搜索失败");
            }

        } catch (IOException e) {
            log.error("读取文件异常", e);
            Asserts.fail("读取文件失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("调用人脸搜索文件接口异常", e);
            Asserts.fail("人脸搜索服务异常: " + e.getMessage());
        }

        return null;
    }

    @Override
    public FaceSearchRespDTO searchFace(String imageBase64, Float threshold, Integer topK) {
        if (StrUtil.isBlank(imageBase64)) {
            Asserts.fail("待搜索的图片数据不能为空");
        }

        try {
            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("image", imageBase64);
            
            if (threshold != null) {
                requestBody.put("threshold", threshold);
            }
            
            if (topK != null) {
                requestBody.put("top_k", topK);
            }

            // 发送请求
            String url = faceRecognitionProperties.getSearchFileUrl();
            log.info("调用人脸搜索接口: {}, threshold: {}, topK: {}", url, threshold, topK);

            String responseBody = faceRecognitionWebClient.post()
                    .uri(url)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(requestBody)
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofMillis(faceRecognitionProperties.getReadTimeout()))
                    .block();

            log.info("人脸搜索接口响应: {}", responseBody);

            // 解析响应（使用 ObjectMapper 正确处理泛型）
            if (StrUtil.isNotBlank(responseBody)) {
                return objectMapper.readValue(responseBody, FaceSearchRespDTO.class);
            } else {
                log.error("人脸搜索接口调用失败: 响应为空");
                Asserts.fail("人脸搜索失败");
            }

        } catch (Exception e) {
            log.error("调用人脸搜索接口异常", e);
            Asserts.fail("人脸搜索服务异常: " + e.getMessage());
        }

        return null;
    }
}
